#include "RangedWeapon.h"
#include "Game.h"
#include "Renderer.h"
#include "StringLib.h"
#include "Ammo.h"

RangedWeapon::RangedWeapon(RangedWeaponType weaponType, RangedWeaponPrefix prefix, RangedWeaponSuffix suffix, bool highQuality, float startAmmo) : Weapon(GT_IT_RANGED_WEAPON, highQuality) {
	m_types[TH_RANGED_WEAPON_TYPE] = weaponType;
	m_prefix = prefix;
	m_suffix = suffix;
	const RangedWeaponInfo& info = g_objectDatabase->getRangedWeaponInfo(weaponType);
	m_types[TH_WEAPON_FAMILY] = info.family;
	m_gripType = info.grip;
	m_ammoType = info.ammo;
	m_maxAmmo = info.maxAmmo;
	m_currentAmmo = int(m_maxAmmo * startAmmo);
	calculateStats(info);
}

RangedWeapon::RangedWeapon(std::ifstream& file) : Weapon(GT_IT_RANGED_WEAPON, file) {
	int* tokens = Util::intSplit(file);
	m_types[TH_RANGED_WEAPON_TYPE] = tokens[0];
	const RangedWeaponInfo& info = g_objectDatabase->getRangedWeaponInfo(RangedWeaponType(tokens[0]));
	m_types[TH_WEAPON_FAMILY] = info.family;
	m_gripType = info.grip;
	calculateStats(info, true);
	m_prefix = RangedWeaponPrefix(tokens[1]);
	m_suffix = RangedWeaponSuffix(tokens[2]);
	m_currentAmmo = tokens[3];
	m_maxAmmo = tokens[4];
	m_range = tokens[5];
	delete[] tokens;
}

RangedWeapon::~RangedWeapon() {
}

void RangedWeapon::save(std::ofstream& file) const {
	file << getType(TH_GENERIC_TYPE) << "\n";
	Weapon::save(file);
	file << getType(TH_RANGED_WEAPON_TYPE) << " " << m_prefix << " " << m_suffix << " " << m_currentAmmo << " " << m_maxAmmo << " " << m_range << "\n";
}

void RangedWeapon::calculateStats(const RangedWeaponInfo& info, bool defaultsOnly) {
	m_defaultNumDice = info.numDie;
	m_defaultDiceSides = info.diceSides;
	m_defaultAttackBonus = info.attackBonus;
	m_defaultAccuracy = info.accuracy;
	m_defaultSpeed = info.speed;
	m_weight = info.weight;
	m_defaultRange = info.range;

	if(!defaultsOnly) {
		m_numDice = m_defaultNumDice;
		m_diceSides = m_defaultDiceSides;
		m_attackBonus = m_defaultAttackBonus;
		m_accuracy = m_defaultAccuracy;
		m_speed = m_defaultSpeed;
		m_range = m_defaultRange;
	}

	m_defaultNumDice = std::max(1, m_defaultNumDice);
	m_defaultDiceSides = std::max(1, m_defaultDiceSides);

	if(!defaultsOnly) {
		/*switch(m_prefix) {
		}

		switch(m_suffix) {
		}*/

		if(m_highQuality) {
			m_numDice++;
			m_diceSides++;
			m_accuracy++;
			m_attackBonus++;
			m_range++;
			m_speed -= 10;
		}
	
		m_numDice = std::max(m_numDice, 1);
		m_diceSides = std::max(m_diceSides, 1);
	}
}

void RangedWeapon::render(float x, float y) {
	g_renderer->render(*this, x, y);
}

std::string RangedWeapon::getItemName(int mod) const {
	std::string output = "";
	if(m_statusIdentified)
		output += g_stringLib->getMiscString(MST_STATUS, m_status) + " ";

	if(m_equippableIdentified) {
		if(m_highQuality)
			output += "high quality ";
		if(m_prefix != RWP_NONE)
			output += g_stringLib->getMiscString(MST_RANGED_WEAPON_PREFIX, m_prefix) + " ";
	} else {
		if(isEnchanted())
			output += "enchanted ";
	}
	if(m_equippableIdentified && m_suffix)
		output += " " + g_stringLib->getMiscString(MST_RANGED_WEAPON_SUFFIX, m_suffix);
	output += getBasicName();
	output += " (" + Util::intToString(m_currentAmmo) + "/" + Util::intToString(m_maxAmmo) + ")";
	if(m_equippableIdentified)
		output += " (" + Util::intToString(m_numDice) + "d" + Util::intToString(m_diceSides) + "" + Util::signIntToString(m_attackBonus) + ", " + Util::signIntToString(m_accuracy) + ", " + Util::intToString(m_speed) + "%)";
	else
		output += " (" + Util::intToString(m_defaultNumDice) + "d" + Util::intToString(m_defaultDiceSides) + "" +
			Util::signIntToString(m_defaultAttackBonus) + ", " + Util::signIntToString(m_defaultAccuracy) + ", " + Util::intToString(m_defaultSpeed) + "%)";
	return output;
}

bool RangedWeapon::isEnchanted() const {
	return m_prefix != RWP_NONE || m_suffix != RWS_OF_NONE || m_highQuality;
}

void RangedWeapon::logDetails(TextLog& log) const {
	Weapon::logDetails(log);
	log.addBlankLine();
	log.addLine(g_stringLib->getTextString(ST_WEAPON_AMMO, Util::intToString(m_currentAmmo).c_str(), Util::intToString(m_maxAmmo).c_str()));
	log.addLine(g_stringLib->getTextString(ST_WEAPON_AMMO_TYPE, g_stringLib->getObjectString(TH_AMMO_TYPE, m_ammoType, 0, true)));
	log.addLine(g_stringLib->getTextString(ST_WEAPON_RANGE, m_equippableIdentified ? Util::intToString(m_range).c_str() : Util::intToString(m_defaultRange).c_str()));
	if(m_equippableIdentified) {
		if(m_prefix != RWP_NONE)
			log.addLine(g_stringLib->getMiscString(MST_RANGED_WEAPON_PREFIX, m_prefix));
		if(m_suffix != RWS_OF_NONE)
			log.addLine(g_stringLib->getMiscString(MST_RANGED_WEAPON_SUFFIX, m_suffix));
	}
}

bool RangedWeapon::reload(Ammo* ammo) {
	if(m_currentAmmo == m_maxAmmo || ammo->getType(TH_AMMO_TYPE) != m_ammoType) return false;
	int numReloaded = std::min(ammo->getNumStacked(), m_maxAmmo-m_currentAmmo);
	m_currentAmmo += numReloaded;
	ammo->reduceStackCount(numReloaded);
	return true;
}
